// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: implementation of CImplInstance.
//   $Id$


#include "stdafx.h"
#include "ImplInstance.h"
#include "model.h"
#include "FP_ReturnCodes.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CImplInstance::CImplInstance(CImplModel* pModel)
	: CImplContent(pModel)
{

}

CImplInstance::~CImplInstance()
{
	//in case the deletion happens during load, set the load event
	//	otherwise, it will return at some unpredictable point in the future.
	if(m_hLoadEvent)
	{
		m_bLoadSuccessful = false;
		SetEvent(m_hLoadEvent);
	}
}


void CImplInstance::onReset()
{
	if(m_pModel)
	{
		m_pModel->onInstanceReset(this,m_pdomLive);
	}
}


#include "WaitWithMessageLoop.h"
#define WAIT_FOR_LOAD_WITH_MESSAGELOOP 1
HRESULT CImplInstance::WaitForLoad()
{
	if(m_hLoadEvent)
	{
		#ifdef WAIT_FOR_LOAD_WITH_MESSAGELOOP
			xport::WaitWithMessageLoop(m_hLoadEvent,INFINITE);
		#else
			::WaitForSingleObject(m_hLoadEvent,INFINITE);	
		#endif
		CloseHandle(m_hLoadEvent);
		m_hLoadEvent = 0;
	}
	return m_bLoadSuccessful?S_OK:E_FAIL;
};

// creates a node in the instance data based on an xpath statement
HRESULT CImplInstance::CreateNode(CNode* pContextNode, BSTR bsXPath, CNode**ppNewNode)
{
	HRESULT hr = S_FALSE;
	//parse the xpath string to see if we can create an appropriate node
	//currently, we cannot create from an XPath with:
	//	Functions  - "("
	//		This may create false matches, parentheses are allowed
	//		as grouping operators in XPath, and in match patterns
	//		for comments and text nodes etc.
	//
	//		Functions will *never* be compatible with this method,
	//		because you cannot ensure that they will always return
	//		the same value, or that they will be called at the
	//		correct time.
	//
	//	Filter Patterns - "["
	//		Filter patterns create complex relationships.  
	//		creating a node with a filter pattern may require
	//		setting values in this or other nodes, which may  
	//		be a difficult decision to make programmatically.
	//		setting values in other nodes or creating multiple nodes
	//		may cause non-obvious behaviour, It requires further analysis
	//
	//	Complex paths - "/"
	//		There is no reason why we cannot do this, just that it
	//		is outside the remit of the current problem set, 
	//		and may have performance issues.  A better parsing method
	//		than simply scanning for characters may be needed
	//		to exclude recursive descent "//" and root setting "/x"
	//		This also excludes ancestor navigation "../" which may be
	//		useful (eg: "../x" to create a sibling called x)
	//

	CStringW sXPath(bsXPath);
	if(sXPath.FindOneOf(L"([/") == -1)
	{
		CComPtr<IXMLDOMDocument> pDoc;
		hr = pContextNode->get_ownerDocument(&pDoc);
		if(SUCCEEDED(hr) && pDoc)
		{
			
			if(sXPath.Find(L'@') == 0)
			{
				//Create an attribute.
				CComQIPtr<IXMLDOMElement> pEl = pContextNode;
				if(pEl)
				{
					pEl->setAttribute(&(bsXPath[1]),CComVariant(""));
					hr = pContextNode->selectSingleNode(bsXPath,ppNewNode);
				}
				else
				{
					hr = E_FAIL;
				}
			}
			else
			{
				//Create an element
				CComPtr<IXMLDOMElement> pEl;
				hr = pDoc->createElement(bsXPath,&pEl);
				if(SUCCEEDED(hr) && pEl)
				{
					pEl->QueryInterface(IID_IXMLDOMNode,(void**)ppNewNode);
					hr = pContextNode->appendChild(*ppNewNode,NULL);
				}
			}
		}

	}



	return hr;
}

#define WAIT_FOR_DOMDOCUMENT_WITH_MESSAGELOOP 1
#undef WAIT_FOR_DOMDOCUMENT_WITH_MESSAGELOOP
HRESULT CImplInstance::putInstanceDocument(IXMLDOMDocument *pDocument)
{
	HRESULT hr = S_OK;
	if(pDocument) {
		CDOM3Document * pDOM = new CDOM3Document(pDocument);
		if(pDOM) {
			if(m_hLoadEvent)
			{
		#ifdef WAIT_FOR_DOMDOCUMENT_WITH_MESSAGELOOP
				xport::WaitWithMessageLoop(m_hLoadEvent,INFINITE);
		#else
				::WaitForSingleObject(m_hLoadEvent,INFINITE);
		#endif
				CloseHandle(m_hLoadEvent);
				m_hLoadEvent = 0;
			}
			m_pModel->RemoveDocumentFromLookupTable(m_pdomLive);
			if(m_pdomLive)
				delete m_pdomLive;
			m_pdomLive = pDOM;
			m_pModel->AddDocumentToLookupTable(this, pDOM);
		} else {
			hr = FP_E_NOMEM;
			SetupErrorInfo(hr, L"");
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CImplInstance::putInstanceDocument");
	}
	return hr;
}
